#!/usr/bin/env python
# -*- coding: utf-8 -*-

import json
from contextlib import contextmanager
from sqlalchemy import create_engine, Column, String, Text, Integer, DateTime, Index, UniqueConstraint
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
import datetime
from scrapy.utils.project import get_project_settings
import logging

logger = logging.getLogger(__name__)
Base = declarative_base()

engine = create_engine(get_project_settings().get('DB_URL'), echo=False, pool_size=5, pool_recycle=5)
Session = sessionmaker(bind=engine)


def init_db(engine):
    try:
        Base.metadata.create_all(engine)
    except Exception as e:
        logger.error('init db failed!!! %s', repr(e))
        raise


def drop_db():
    try:
        Base.metadata.drop_all(engine)
    except Exception as e:
        logger.error('drop db failed!!! %s', repr(e))
        raise


# init_db(engine)

def get_sqlsession(engine):
    try:
        session = Session()
        return session
    except Exception as e:
        logger.error('get sqlsession failed!!! %s', repr(e))
        raise e


class BaseModel(Base):
    __abstract__ = True

    @staticmethod
    def set_attrs(attrs_datas, obj):
        if not isinstance(attrs_datas, dict):
            try:
                attrs_datas = json.loads(attrs_datas)
            except Exception as e:
                raise e

        for k, v in attrs_datas.items():
            if hasattr(obj, k) and k != 'id':  # 非id属性
                setattr(obj, k, str(v))

    @classmethod
    def save_model(cls, model, item):
        if item:
            if hasattr(item, '__dict__'):
                item_data = item.__dict__['_values']
            else:
                item_data = item
            cls.set_attrs(item_data, model)

            try:
                session = get_sqlsession(engine)
                session.add(model)
                session.commit()
            except Exception as e:
                session.rollback()
                print('save model falied,', e)
            finally:
                session.close()

    @staticmethod
    @contextmanager
    def auto_commit():
        try:
            session = get_sqlsession(engine)
            yield session.commit()
        except Exception as e:
            session.rollback()
            print('auto commit falied,', e)
        finally:
            session.close()


class MedicineModel(BaseModel):
    __tablename__ = 't_medicine'

    source_url = Column(String(100), primary_key=True, comment='网页地址')
    name = Column(String(200), default='', comment='产品名称|药品名称')
    category1 = Column(String(80), default='', comment='分类1')
    category2 = Column(String(80), default='', comment='分类2')
    price_retail = Column(String(200), default='', comment='零售价格')
    spec = Column(String(200), default='', comment='规格')
    dosage_form = Column(String(500), default='', comment='剂型')
    package_unit = Column(String(20), default='', comment='包装单位')
    approval_number = Column(String(120), default='', comment='批准文号')
    prescription = Column(String(20), default='0', comment='是否处方药')
    producer = Column((String(200)), default='', comment='生产厂家')
    barcode = Column(String(40), default='', comment='条形码')
    attending = Column(String(500), default='', comment='主治疾病')
    instructions = Column(Text(), default='', comment='说明书')
    image_url = Column(Text(), default='', comment='说明图片书')
    gmt_create = Column(DateTime, default=datetime.datetime.now, comment='创建时间')
    gmt_update = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now, comment='更新时间')

    __table_args__ = (
        {'comment': '药品'}
    )

    @classmethod
    def save_model(cls, model, item):
        try:
            session = get_sqlsession(engine)
            data = session.query(cls).filter(cls.source_url == item['source_url']).first()
            if data:
                cls.set_attrs(item.__dict__['_values'], data)
            else:
                cls.set_attrs(item.__dict__['_values'], model)
                session.add(model)

            session.commit()
        except Exception as e:
            session.rollback()
            print('save model falied,', e)
        finally:
            session.close()

